package com.monster.starter.exception.service.impl;

import com.monster.exception.SystemException;
import com.monster.exception.impl.MonsterNoTackException;
import com.monster.starter.exception.common.ExceptionUtils;
import com.monster.starter.exception.service.MonsterExceptionService;
import com.monster.utils.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * 异常处理实现
 *
 * @author kuang
 */
@Slf4j
@Component
public class MonsterExceptionServiceImpl implements MonsterExceptionService {
    /**
     * 统一处理异常
     */
    @Autowired
    private ExceptionUtils utils;

    /**
     * 获取最底层的异常
     *
     * @param e 异常
     * @return 异常信息
     */
    private Throwable getException(Throwable e) {
        if (e.getCause() != null) {
            return getException(e.getCause());
        }
        return e;
    }

    /**
     * 异常处理
     *
     * @param request  请求对象
     * @param response 响应对象
     * @param e        异常对象
     */
    @Override
    public void exceptionHandler(HttpServletRequest request, HttpServletResponse response, Throwable e) {
        // 设置返回请求头，返回状态
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(200);
        // 解析异常获得最底层的异常
        e = getException(e);
        // 打印异常信息
        showStack(e, request);
        // 获取凑得和message
        String code , msg;
        if (e instanceof SystemException ex) {
            code = utils.getCode(ex.getCode());
            msg = utils.getMessage(ex.getMsg());
        } else {
            code = utils.getCode(null);
            msg = utils.getMessage(null);
        }

        // 写入返回数据
        try (PrintWriter out = response.getWriter()) {
            out.write(utils.createResultString(code, msg, null));
            out.flush();
        } catch (IOException ioException) {
            log.error("写入返回数据失败！", e);
        }
    }


    /**
     * 打印异常堆栈信息
     *
     * @param e 异常
     */
    private void showStack(Throwable e, HttpServletRequest request) {
        // 关闭异常堆栈打印和不打印堆栈信息的异常
        if (e instanceof MonsterNoTackException || !utils.getExceptionConfig().isStack()) {
            String seatStr = "";
            if (e.getStackTrace() != null) {
                StackTraceElement stackTraceElement = e.getStackTrace()[0];
                seatStr = StringUtils.format(">>>>>>>>>>错误文件名称：{}，方法：{}，行号：{}", stackTraceElement.getClassName(), stackTraceElement.getMethodName(), stackTraceElement.getLineNumber());

            }
            log.info("======错误信息【{}：{}】 {}", utils.getCode(e instanceof SystemException ? ((SystemException) e).getCode() : null), e.getMessage(), seatStr);
        } else {
            if (e instanceof SystemException ex) {
                log.error("======错误信息【{}，{}】", utils.getCode(ex.getCode()), e.getMessage(), e);
            } else {
                log.error("======错误信息【{}，{}】", utils.getCode(null), e.getMessage(), e);
            }
        }
    }
}
